﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Management;
using System.Diagnostics;
using System.IO;

namespace Manager2070.Library
{
    public class Game
    {
        public event EventHandler OnGameReady;
        public event EventHandler OnGameNotReady;
        public event EventHandler OnGameEnded;

        private ManagementEventWatcher _watchUbiStart = null;
        private ManagementEventWatcher _watchUbiStop = null;
        private ManagementEventWatcher _watchAnnoStop = null;

        private string _thisGameInstallDir = null;
        private string _thisGameExecutable = null;

        private bool _IsGameInstalled = false;

        public bool IsGameInstalled
        {
            get { return _IsGameInstalled; }
        }

        public string InstallationDirectory
        {
            get { return _thisGameInstallDir; }
        }

        public Game()
        {
            _IsGameInstalled = IsGameInstalled2(out _thisGameInstallDir, out _thisGameExecutable);
        }

        public bool IsUbiLauncherRunning()
        {
            return ProcessTools.IsProcessRunning((System.Configuration.ConfigurationManager.AppSettings["UbiSoftGameLauncherBin"] as string).ToUpper().Replace(".EXE", ""));
        }

        private bool IsGameInstalled2(out string installDir, out string gameExecutable)
        {
            installDir = null;
            gameExecutable = null;
            RegistryKey gameKey = Registry.LocalMachine.OpenSubKey(System.Configuration.ConfigurationManager.AppSettings["RegistryGameKey"], false);
            
            if (gameKey !=null)
            {
                gameExecutable = gameKey.GetValue(System.Configuration.ConfigurationManager.AppSettings["RegistryGameValueExecutable"], null) as string;
                installDir = gameKey.GetValue(System.Configuration.ConfigurationManager.AppSettings["RegistryGameValueInstallDir"], null) as string;
            }

            if (gameKey == null || gameExecutable == null || installDir == null)
                return false;
            else
                return true;
        }

        public string GetNewestPatchPath()
        {
            if (_IsGameInstalled)
            {
                List<string> s = Directory.EnumerateFiles(Path.Combine(_thisGameInstallDir + System.Configuration.ConfigurationManager.AppSettings["GamePatchFolder"]), System.Configuration.ConfigurationManager.AppSettings["GamePatchSearchPattern"])
                    .OrderBy(f => f, new NaturalSortComparer<string>())
                    .ToList();

                return s.LastOrDefault();

            }
            else
            {
                return null;
            }

        }

        public bool LaunchGame(bool isOnline = true)
        {
            ProcessTools ptools = new ProcessTools();
            bool gamestarted = true;

            // check for launcher
            if (! IsUbiLauncherRunning())
            {
                // start anno5
                if (_IsGameInstalled)
                {
                    //_thisGameExecutable2 = Path.Combine(installDir, System.Configuration.ConfigurationManager.AppSettings["AutoPatcherBin"] as string);
                    gamestarted = ProcessTools.StartProcess(_thisGameExecutable,
                        !isOnline ? System.Configuration.ConfigurationManager.AppSettings["GameOfflineArguments"] as string : System.Configuration.ConfigurationManager.AppSettings["GameOnlineArguments"] as string);

                    if (gamestarted)
                    {
                        // watch for launcher
                        WatchUbiStart();
                    }
                }
                else
                    return false;
            }
            else
            {
                WatchUbiStop();

                if (OnGameReady != null)
                    OnGameReady(null, new EventArgs());
            }

            return gamestarted;
        }

        private void WatchUbiStop()
        {
            if (_watchUbiStop != null) return;  
            // if you start game and the launcher is not running then this will be hit, 
            //  then you click cancel on the patcher screen, and start game again,
            //  the launcher is already running so this code will be attempted to be hit again.

            _watchUbiStop = new ProcessTools().CreateWatcherForProcessEnd(System.Configuration.ConfigurationManager.AppSettings["UbiSoftGameLauncherBin"] as string);
            _watchUbiStop.EventArrived += new EventArrivedEventHandler(_watchUbiStop_EventArrived);
            _watchUbiStop.Start();
        }

        private void UnwatchUbiStop()
        {
            _watchUbiStop.Stop();
            _watchUbiStop.EventArrived -= new EventArrivedEventHandler(_watchUbiStop_EventArrived);
            _watchUbiStop.Dispose();
            _watchUbiStop = null;
        }

        private void WatchUbiStart()
        {
            _watchUbiStart = new ProcessTools().CreateWatcherForProcessStart(System.Configuration.ConfigurationManager.AppSettings["UbiSoftGameLauncherBin"] as string);
            _watchUbiStart.EventArrived += new EventArrivedEventHandler(_watchUbiStart_EventArrived);
            _watchUbiStart.Start();
        }

        private void UnwatchUbiStart()
        {
            _watchUbiStart.Stop();
            _watchUbiStart.EventArrived -= new EventArrivedEventHandler(_watchUbiStart_EventArrived);
            _watchUbiStart.Dispose();
            _watchUbiStart = null;
        }

        private void WatchAnnoStop()
        {
            _watchAnnoStop = new ProcessTools().CreateWatcherForProcessEnd(Path.GetFileName(_thisGameExecutable));
            _watchAnnoStop.EventArrived += new EventArrivedEventHandler(_watchAnnoStop_EventArrived);
            _watchAnnoStop.Start();
        }

        private void UnwatchAnnoStop()
        {
            if (_watchAnnoStop == null) return;

            _watchAnnoStop.Stop();
            _watchAnnoStop.EventArrived -= new EventArrivedEventHandler(_watchAnnoStop_EventArrived);
            _watchAnnoStop.Dispose();
            _watchAnnoStop = null;
        }

        void _watchUbiStop_EventArrived(object sender, EventArrivedEventArgs e)
        {
            UnwatchUbiStop();

            UnwatchAnnoStop();

            if (OnGameNotReady != null)
                OnGameNotReady(null, new EventArgs());
        }

        void _watchAnnoStop_EventArrived(object sender, EventArrivedEventArgs e)
        {
            UnwatchAnnoStop();

            if (OnGameEnded != null)
                OnGameEnded(null, new EventArgs());
        }

        void _watchUbiStart_EventArrived(object sender, EventArrivedEventArgs e)
        {
            UnwatchUbiStart();

            WatchUbiStop();

            WatchAnnoStop();

            if (OnGameReady != null)
                OnGameReady(null, new EventArgs());
        }
    }
}
